Jerry's Log

Covering Index

contents

쿼리 최적화의 "성배(Holy Grail)"로 불리는 커버링 인덱스(Covering Index) 에 대해 알아보겠습니다.


1. 커버링 인덱스란?

커버링 인덱스는 쿼리를 충족시키는 데 필요한 모든 컬럼을 가지고 있는 인덱스를 말합니다.

왜 빠른가요?

데이터를 찾기 위해 여기저기 디스크를 뒤지는 "랜덤 I/O" 과정을 없애고, 메모리에서 순차적으로 읽기만 하면 되기 때문입니다. 일종의 '초고속 지름길'입니다.


2. 비유: "도서관 검색대"

도서관에서 "해리 포터" 책의 출판 연도를 알고 싶다고 가정해 봅시다.


3. EXPLAIN에서 확인하는 법

쿼리가 커버링 인덱스를 제대로 타고 있다면, MySQL EXPLAIN 계획의 Extra 컬럼에 다음과 같이 표시됩니다.

주의: type: index(느린 전체 인덱스 스캔)와 혼동하지 마세요. Extra: Using index가 나와야 합니다.


4. 실전 예시

테이블: Orders (id, customer_id, product_id, amount, order_date)

인덱스: CREATE INDEX idx_cust_date ON Orders (customer_id, order_date);

쿼리 A: 커버링 안 됨 (느림)

SELECT amount FROM Orders 
WHERE customer_id = 101 
AND order_date = '2024-01-01';

쿼리 B: 커버링 됨 (빠름)

SELECT order_date FROM Orders 
WHERE customer_id = 101;

5. 커버링 인덱스 만드는 법 (INCLUDE 절)

만약 쿼리 A(amount 조회)도 빠르게 만들고 싶다면 어떻게 할까요?

두 가지 방법이 있습니다.

방법 1: 키에 추가하기 (MySQL 표준)

-- 데이터가 고객 -> 날짜 -> 금액 순으로 정렬됨
CREATE INDEX idx_covering ON Orders (customer_id, order_date, amount);

방법 2: INCLUDE 절 사용 (PostgreSQL / SQL Server)

이 방법이 더 효율적입니다. amount를 인덱스의 "리프 노드(Leaf Node)"에만 덧붙여 저장하고, 정렬에는 사용하지 않습니다. 인덱스 트리를 더 작고 깔끔하게 유지할 수 있습니다.

CREATE INDEX idx_covering 
ON Orders (customer_id, order_date) 
INCLUDE (amount); 

6. 장단점

장점 단점
속도: 읽기 작업 중 가장 비싼 비용인 '테이블 조회'를 제거합니다. 크기: 인덱스 크기가 커집니다 (RAM/디스크 더 차지함).
I/O: 디스크 I/O를 획기적으로 줄입니다. 유지보수: INSERTUPDATE가 발생할 때마다 더 커진 인덱스를 갱신해야 하므로 쓰기 속도가 약간 느려집니다.

references